package com.mxpio.erp.quality.service.impl;

import com.mxpio.erp.common.LotStatusUtil;
import com.mxpio.erp.common.enums.InspectionEnums;
import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.*;
import com.mxpio.erp.common.inventory.service.LotService;
import com.mxpio.erp.common.jpa.entity.BizNoticeType;
import com.mxpio.erp.common.jpa.model.NoticeLineKey;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.jpa.model.QualityOrder;
import com.mxpio.erp.common.jpa.model.QualityOrderLine;
import com.mxpio.erp.common.quality.entity.*;
import com.mxpio.erp.common.quality.service.UnqualifiedDisposalService;
import com.mxpio.erp.common.technology.entity.Item;
import com.mxpio.erp.common.vo.UnqualifiedDisposalAuditVO;
import com.mxpio.erp.common.workshop.entity.*;
import com.mxpioframework.common.exception.MBootException;
import com.mxpioframework.common.vo.Result;
import com.mxpio.erp.quality.utils.QualityUtils;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.lin.Linu;
import com.mxpioframework.jpa.policy.CrudContext;
import com.mxpioframework.jpa.policy.impl.CrudType;
import com.mxpioframework.jpa.policy.impl.SmartCrudPolicyAdapter;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.security.util.SecurityUtils;
import com.mxpioframework.system.service.SnRuleService;
import com.mxpioframework.system.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UnqualifiedDisposalServiceImpl extends BaseServiceImpl<UnqualifiedDisposal> implements UnqualifiedDisposalService {
    @Autowired
    private LotService lotService;
    @Autowired
    private SnRuleService snRuleService;

    //public static final String REWORK_TYPE = "03";//返工类型订单

    @Override
    @Transactional
    public Result<UnqualifiedDisposal> audit(UnqualifiedDisposalAuditVO auditVO) {
        String bizNo = auditVO.getBizNo();
        UnqualifiedDisposal byId = this.getById(UnqualifiedDisposal.class, bizNo);
        if (byId==null){
            return Result.error("入参对象中的bizNo无效");
        }else if (byId.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode())){
            return Result.error("单据已关闭，无法审核！");
        }else if (auditVO.getAuditType().equals("3")&&(StringUtils.isBlank(byId.getTechOpinion())||StringUtils.isBlank(byId.getCraftOpinion()))){
            return Result.error("质检审核之前，需要工艺和技术审核！");
        }
        String auditType = auditVO.getAuditType();
        String opinion = auditVO.getOpinion();
        if (StringUtils.equals(auditType,"1")){//技术审核
            byId.setTechOpinion(auditVO.getOpinion());
            byId.setTechOpinionDesc(auditVO.getOpinionDesc());
            byId.setTechReviewer(SecurityUtils.getLoginUsername());
            byId.setTechReviewTime(new Date());
            if (opinion.equals("03")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
            }else if (opinion.equals("02")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode());
            }
        }else if (StringUtils.equals(auditType,"2")){//工艺审核
            byId.setCraftOpinion(auditVO.getOpinion());
            byId.setCraftOpinionDesc(auditVO.getOpinionDesc());
            byId.setCraftReviewer(SecurityUtils.getLoginUsername());
            byId.setCraftReviewTime(new Date());
            if (opinion.equals("03")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
            }else if (opinion.equals("02")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode());
            }
        }else if (StringUtils.equals(auditType,"3")){//质检审核
            byId.setQualityOpinion(auditVO.getOpinion());
            byId.setQualityOpinionDesc(auditVO.getOpinionDesc());
            byId.setQualityReviewer(SecurityUtils.getLoginUsername());
            byId.setQualityReviewTime(new Date());
            if (opinion.equals("03")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode());
            }else if (opinion.equals("02")){//01,同意，03驳回，02不同意
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode());
            }else{
                byId.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());//审核通过
            }
            //审核同意
            if (opinion.equals("01")){//质检同意
                List<UnqualifiedDisposalLine> lines = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class , "inspectionBillNo").equal("bizNo", bizNo).list();
                //质检单来源单类型，1采购验收，2生产验收，3委外验收  InspectionEnums

                List<UnqualifiedDisposalLine> recList = new ArrayList<>();//让步接收
                List<UnqualifiedDisposalLine> moRewList = new ArrayList<>();//生产返工
                List<UnqualifiedDisposalLine> ooRewList = new ArrayList<>();//委外返工
                List<UnqualifiedDisposalLine> scrList = new ArrayList<>();//报废

                for (UnqualifiedDisposalLine line:lines){
                    InspectionBill inspectionBill = line.getInspectionBill();
                    if (inspectionBill==null){
                        throw new MBootException("未正常关联到质检单！");
                    }
                    String applyDecision = line.getApplyDecision();//申请决策
                    if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.PURCH.getCode())){//采购
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REJ.getCode())){//判退 不处理
                            //判退时，不处理
                            handleRej(line);
                        }else{
                            throw new MBootException("采购业务单仅支持让步接收和判退两种使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.MANF.getCode())){//生产
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                            moRewList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                            scrList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REF.getCode())){//返修
                            //todo 返修逻辑暂不处理
                        }else{
                            throw new MBootException("生产业务单不支持的使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.OUTS.getCode())){//委外
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                            ooRewList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                            scrList.add(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REF.getCode())){//返修
                            //todo 返修逻辑暂不处理
                        }else{
                            throw new MBootException("委外业务单不支持的使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.INVENTORY.getCode())){//库存质检
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                            scrList.add(line);
                        }else{
                            throw new MBootException("库存质检业务单仅支持让步接收和报废两种使用决策！");
                        }
                    }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.SALERE.getCode())){//销售退货
                        if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                            handleRec(line);
                        }else if (applyDecision.equals(InspectionEnums.UsageDecision.REJ.getCode())){//判退 不处理
                            //判退时，不处理
                            handleRej(line);
                        }else{
                            throw new MBootException("销售退货业务单仅支持让步接收和判退两种使用决策！");
                        }
                    }else{
                        throw new MBootException("质检单业务类型有误！");//实际业务不会走到该逻辑
                    }
                }
                if (moRewList.size()>0){//处理生产返工订单
                    Map<String, List<UnqualifiedDisposalLine>> origBizNoMap = moRewList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill().getOriginBizNo()));
                    for (String origBizNo :origBizNoMap.keySet()){
                        handleRew(origBizNoMap.get(origBizNo),false);
                    }
                }
                if (ooRewList.size()>0){//委外返工订单
                    Map<String, List<UnqualifiedDisposalLine>> origBizNoMap = ooRewList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill().getOriginBizNo()));
                    for (String origBizNo :origBizNoMap.keySet()){
                        handleRew(origBizNoMap.get(origBizNo),false);
                    }
                }
                if (scrList.size()>0){
                    handleScr(scrList,false);
                }
            }
        }
        JpaUtil.update(byId);//更新数据
        return Result.OK(byId);
    }

    @Override
    @Transactional
    public Result<UnqualifiedDisposal> saveWithCheck(UnqualifiedDisposal disposal) {
        this.save(disposal,new SmartCrudPolicyAdapter(){
            @Override
            public boolean beforeInsert(CrudContext context) {
                Object o = context.getEntity();
                if(o instanceof UnqualifiedDisposalLine){
                    UnqualifiedDisposal scrapOutApply = context.getParent();
                    ((UnqualifiedDisposalLine) o).setBizNo(scrapOutApply.getBizNo());
                }
                return true;
            }
        });
        List<UnqualifiedDisposalLine> lineList = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class, "inspectionBillNo").equal("bizNo", disposal.getBizNo()).list();
        checkOriginBizDecision(lineList);
        return Result.OK(disposal);
    }


    private void handleRec(UnqualifiedDisposalLine line){
        this.lotSplitByApplyDecision(line);
    }
    private void handleRej(UnqualifiedDisposalLine line){
        InspectionBill inspectionBill = line.getInspectionBill();
        //回写判断数量
        JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("refundQuantity",line.getApplyQuantity()).update();
        //如果业务单类型是采购、且判断数量等于质检单的送检数量，表示整单拒掉，这个时候，如果是送货计划，需要拒掉送货计划对应的领料单
        if (StringUtils.equals(InspectionEnums.OriginBizType.PURCH.getCode(),inspectionBill.getOriginBizType())
                &&inspectionBill.getQuantity().compareTo(line.getApplyQuantity())==0){
            String originNoticeNo = inspectionBill.getOriginNoticeNo();
            InQualityOrder inQualityOrder = JpaUtil.getOne(InQualityOrder.class, originNoticeNo);
            if (inQualityOrder!=null && StringUtils.isNotBlank(inQualityOrder.getFeedPlanNoticeNo())){
                FeedPlanNotice feedPlanNotice = JpaUtil.getOne(FeedPlanNotice.class, inQualityOrder.getFeedPlanNoticeNo());
                MoPickingNotice pickingNotice = JpaUtil.linq(MoPickingNotice.class).collect("noticeNo", MoPickingNoticeLine.class, "noticeNo")
                        .equal("noticeNo", feedPlanNotice.getSourcePickingNoticeNo()).findOne();
                pickingNotice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.REJECT.getStatusCode());//确认状态
                JpaUtil.update(pickingNotice);
            }
        }
    }


    @Override
    @Transactional(readOnly = true)
    public Page<VInvLotStock> lotPageUDUnRefer(Pageable pageAble, Criteria c) {//不良品批次，未被不合格品单引用的批次
        Set<String> bizNos = null;
        List<UnqualifiedDisposal> unCloseUDList = JpaUtil.linq(UnqualifiedDisposal.class).notEqual("bpmnStatus", OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode()).list();
        if (unCloseUDList.size()>0){//查找非关闭不良品处理单的单号
            bizNos = unCloseUDList.stream().map(UnqualifiedDisposal::getBizNo).collect(Collectors.toSet());
        }
        if (CollectionUtils.isEmpty(bizNos)){
            return JpaUtil.linq(VInvLotStock.class)
                    .collect("bizNo", InspectionBill.class, "inspectionBillNo")
                    .like("lotStatus","_______________1").gt("quantity",0).where(c).paging(pageAble);
        }else{
            return JpaUtil.linq(VInvLotStock.class)
                    .collect("bizNo", InspectionBill.class, "inspectionBillNo")
                    .like("lotStatus","_______________1")
                    .gt("quantity",0)
                    .notExists(UnqualifiedDisposalLine.class)
                    .equalProperty("lotNo", "lotNo")
                    .equalProperty("subLotIndex", "subLotIndex")
                        .in("bizNo", bizNos)
                    .end()
                    .where(c)
                    .paging(pageAble);
        }
    }

    @Override
    @Transactional(readOnly = false)
    public Result<? extends Order> submitOrder(String bizNo) {
        UnqualifiedDisposal po = this.getById(UnqualifiedDisposal.class, bizNo);
        if (!po.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())) {
            return Result.error("非开立状态不可提交");
        }
        //提交时 ，检查 历史审核意见，并清空(处理驳回)
        if (StringUtils.isNotBlank(po.getTechOpinion())){
            po.setTechOpinion(null);
            po.setTechOpinionDesc(null);
            po.setTechReviewer(null);
            po.setTechReviewTime(null);
        }
        if (StringUtils.isNotBlank(po.getCraftOpinion())){
            po.setCraftOpinion(null);
            po.setCraftOpinionDesc(null);
            po.setCraftReviewer(null);
            po.setCraftReviewTime(null);
        }
        if (StringUtils.isNotBlank(po.getQualityOpinion())){
            po.setQualityOpinion(null);
            po.setQualityOpinionDesc(null);
            po.setQualityReviewer(null);
            po.setQualityReviewTime(null);
        }
        po.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode());
        po.setReviewer(SecurityUtils.getLoginUsername());
        po.setReviewTime(new Date());
        po.setSubmitTime(new Date());//提交时间
        return Result.OK(po);
    }

    //原拆批逻辑（有原批次信息）
    @Deprecated
    private void lotSplitByApplyDecision(UnqualifiedDisposalLine line){
        InspectionBill inspectionBill = line.getInspectionBill();
        String originBizType = inspectionBill.getOriginBizType();
        String applyDecision = line.getApplyDecision();
        //不合并让步接收对应flow出入的仓单，单条数据一仓单一明细
        //拆批，对应库存转移
        WarehouseOrder outWo = new WarehouseOrder();
        outWo.setAccessType(OrderEnums.AccessType.OUT.getCode());
        outWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        outWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        outWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        outWo.setOrderDate(new Date());
        outWo.setOriginBizNo(inspectionBill.getOriginBizNo());
        outWo.setWhCode(line.getWhCode());
        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){//返工
            outWo.setWoType(NoticeStatusEnums.NoticeType.QREW_OUT.getCode());//("52", "不良品处理-返工-转移出")
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){//报废
            outWo.setWoType(NoticeStatusEnums.NoticeType.QSCR_OUT.getCode());//("54", "不良品处理-报废-转移出")
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            outWo.setWoType(NoticeStatusEnums.NoticeType.QO_OUT.getCode());//QO_OUT("50", "质检让步接收出")
        }
        outWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段
        outWo.setExecuteTime(new Date());
        outWo.setExecutor("8888");//自动化助手，默认指定用户
        JpaUtil.save(outWo);
        WarehouseOrderLine outWoLine = new WarehouseOrderLine();
        outWoLine.setWhCode(outWo.getWhCode());
        outWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        Item item = JpaUtil.linq(Item.class).idEqual(inspectionBill.getItemCode()).findOne();
        if (item!=null){
            outWoLine.setItemCode(item.getItemCode());
            outWoLine.setItemGroupCode(item.getItemGroupCode());
            outWoLine.setItemName(item.getItemName());
            outWoLine.setItemSpec(item.getItemSpec());
            outWoLine.setUnitCode(item.getUnitCode());
            outWoLine.setDrawingNo(item.getDrawingNo());
        }
        outWoLine.setQuantity(line.getApplyQuantity());//申请数量
        outWoLine.setBizNo(outWo.getBizNo());
        outWoLine.setLineNo("1");
        outWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        outWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        outWoLine.setSort("1");

        outWoLine.setLotNo(line.getLotNo());
        outWoLine.setSubLotIndex(line.getSubLotIndex());
        outWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        outWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(outWoLine);


        //不合格品批 让步接收转入仓单
        WarehouseOrder inWo = new WarehouseOrder();
        inWo.setAccessType(OrderEnums.AccessType.IN.getCode());
        inWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        inWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        inWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        inWo.setOrderDate(new Date());
        inWo.setOriginBizNo(inspectionBill.getOriginBizNo());

        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){//返工
            inWo.setWoType(NoticeStatusEnums.NoticeType.QREW_IN.getCode());//("53", "不良品处理-返工-转移入")
            //取原不合格批对应仓库
            inWo.setWhCode(line.getWhCode());
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){//报废
            inWo.setWoType(NoticeStatusEnums.NoticeType.QSCR_IN.getCode());//("55", "不良品处理-报废-转移入")
            //取原不合格批对应仓库
            inWo.setWhCode(line.getWhCode());
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            inWo.setWoType(NoticeStatusEnums.NoticeType.QO_IN.getCode());//QO_IN("51", "质检让步接收入"),
            //让步接收 仓库取原验收单对应仓库
            if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
                InQualityOrder inQualityOrder = JpaUtil.getOne(InQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(inQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
                MoInQualityOrder moInQualityOrder = JpaUtil.getOne(MoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(moInQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
                OoInQualityOrder ooInQualityOrder = JpaUtil.getOne(OoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(ooInQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.INVENTORY.getCode())){
                InventoryQualityOrder inventoryQualityOrder = JpaUtil.getOne(InventoryQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(inventoryQualityOrder.getWhCode());//
            }else if (originBizType.equals(InspectionEnums.OriginBizType.SALERE.getCode())){
                SoInQualityOrder soInQualityOrder = JpaUtil.getOne(SoInQualityOrder.class, inspectionBill.getOriginNoticeNo());
                inWo.setWhCode(soInQualityOrder.getWhCode());//
            }
        }else{
            throw new MBootException("无效的申请使用决策");
        }
        inWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段
        inWo.setExecuteTime(new Date());
        inWo.setExecutor("8888");//自动化助手，默认指定用户
        JpaUtil.save(inWo);
        WarehouseOrderLine inWoLine = new WarehouseOrderLine();
        inWoLine.setWhCode(inWo.getWhCode());
        inWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        if (item!=null){
            inWoLine.setItemCode(item.getItemCode());
            inWoLine.setItemGroupCode(item.getItemGroupCode());
            inWoLine.setItemName(item.getItemName());
            inWoLine.setItemSpec(item.getItemSpec());
            inWoLine.setUnitCode(item.getUnitCode());
            inWoLine.setDrawingNo(item.getDrawingNo());
        }
        inWoLine.setQuantity(line.getApplyQuantity());//申请数量
        inWoLine.setBizNo(inWo.getBizNo());
        inWoLine.setLineNo("1");
        inWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        inWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        inWoLine.setSort("1");

        //拆批
        //记录新批次号
        Lot lot = new Lot();
        lot.setLotNo(line.getLotNo());
        lot.setSubLotIndex(lotService.getCountByLotNo(line.getLotNo()).toString());//索引
        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            lot.setLotStatus(LotStatusUtil.toBinaryString("0"));//让步接收改为正常
        }else{
            String binaryString = LotStatusUtil.toBinaryString("0");//默认正常
            lot.setLotStatus(LotStatusUtil.switchBinaryByIndex(binaryString,InspectionEnums.LotStatusBitIndex.IB15.getIndex()));//和源批状态保持一致
        }
        lot.setInspectionBillNo(inspectionBill.getBizNo());//不合格品批次生成时记录对应的质检单单号 溯源
        JpaUtil.save(lot);

        inWoLine.setLotNo(lot.getLotNo());
        inWoLine.setSubLotIndex(lot.getSubLotIndex());//新批次
        inWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        inWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(inWoLine);

        //出流水
        InvFlow outFlow = new InvFlow();
        outFlow.setAccessType(outWo.getAccessType());
        outFlow.setItemCode(outWoLine.getItemCode());
        outFlow.setWhCode(outWo.getWhCode());
        outFlow.setQuantity(outWoLine.getQuantity());
        outFlow.setMemo(outWo.getMemo());
        outFlow.setOriginBizNo(outWo.getOriginBizNo());
        outFlow.setOriginBizType(outWo.getOriginBizType());
        outFlow.setOriginBizLineNo(outWoLine.getOriginBizLineNo());
        outFlow.setWoBizNo(outWo.getBizNo());
        outFlow.setWoBizType(outWo.getWoType());
        outFlow.setWoBizLineNo(outWoLine.getLineNo());
        outFlow.setLotNo(outWoLine.getLotNo());
        outFlow.setSubLotIndex(outWoLine.getSubLotIndex());//增加子批索引
        JpaUtil.save(outFlow);

        //入
        InvFlow inFlow = new InvFlow();
        inFlow.setAccessType(inWo.getAccessType());
        inFlow.setItemCode(inWoLine.getItemCode());
        inFlow.setWhCode(inWo.getWhCode());
        inFlow.setQuantity(inWoLine.getQuantity());
        inFlow.setMemo(inWo.getMemo());
        inFlow.setOriginBizNo(inWo.getOriginBizNo());
        inFlow.setOriginBizType(inWo.getOriginBizType());
        inFlow.setOriginBizLineNo(inWoLine.getOriginBizLineNo());
        inFlow.setWoBizNo(inWo.getBizNo());
        inFlow.setWoBizType(inWo.getWoType());
        inFlow.setWoBizLineNo(inWoLine.getLineNo());
        inFlow.setLotNo(inWoLine.getLotNo());
        inFlow.setSubLotIndex(inWoLine.getSubLotIndex());//增加子批索引
        JpaUtil.save(inFlow);

        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            //回写让步接收数量(质检单)
            JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("concessionQuantity",inFlow.getQuantity()).update();
            //回写让步接收数量(验收单)
            Linu linu = null;
            if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
                linu = JpaUtil.linu(InQualityOrderLine.class);
            }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
                linu = JpaUtil.linu(MoInQualityOrderLine.class);
            }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
                linu = JpaUtil.linu(OoInQualityOrderLine.class);
            }

            if (linu!=null){//更新验收单明细行对应的让步=接收数量
                linu.equal("noticeNo",inspectionBill.getOriginNoticeNo())
                        .equal("lineNo",inspectionBill.getOriginNoticeLineNo())
                        .set("concessionQuantity",inFlow.getQuantity()).update();
            }
        }
        line.setSplitNewLotNo(inFlow.getLotNo());
        line.setSplitNewSubLotIndex(inFlow.getSubLotIndex());
        line.setSplitNewWhCode(inFlow.getWhCode());//供下游生成报废申请单使用
        //不良品明细行回写新拆批信息
        JpaUtil.linu(UnqualifiedDisposalLine.class).equal("id",line.getId())
                .set("splitNewWhCode",inFlow.getWhCode())
                .set("splitNewLotNo",inFlow.getLotNo())
                .set("splitNewSubLotIndex",inFlow.getSubLotIndex())
                .update();
    }

    @Override
    @Transactional
    public Result<UnqualifiedDisposal> saveAndPass(UnqualifiedDisposal disposal) {
        String bizNo = disposal.getBizNo();
        UnqualifiedDisposal dbEntity = this.getById(UnqualifiedDisposal.class, bizNo);
        if (dbEntity.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CLOSED.getStatusCode())){
            throw new MBootException("单据已关闭，无法审核！");
        }else if (dbEntity.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())){
            throw new MBootException("单据已审核，无法重复审核！");
        }
        dbEntity.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());//更新数据状态为已审核
        this.update(dbEntity);
        List<UnqualifiedDisposalLine> updateLines = disposal.getUnqualifiedDisposalLines();
        if (updateLines!=null&& !updateLines.isEmpty()){
            for (UnqualifiedDisposalLine line:updateLines){
                if (StringUtils.isBlank(line.getBizNo())){
                    line.setBizNo(dbEntity.getBizNo());
                }
            }
            JpaUtil.save(updateLines);
        }

        List<UnqualifiedDisposalLine> lineList = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class, "inspectionBillNo").equal("bizNo", disposal.getBizNo()).list();
        checkOriginBizDecision(lineList);
        auditPass(dbEntity,lineList);
        return Result.OK(dbEntity);
    }

    private void auditPass(UnqualifiedDisposal disposal,List<UnqualifiedDisposalLine> lines){
        //List<UnqualifiedDisposalLine> lines = JpaUtil.linq(UnqualifiedDisposalLine.class).collect("bizNo", InspectionBill.class , "inspectionBillNo").equal("bizNo", disposal.getBizNo()).list();
        //质检单来源单类型，1采购验收，2生产验收，3委外验收  InspectionEnums

        List<UnqualifiedDisposalLine> moRewList = new ArrayList<>();//生产返工
        List<UnqualifiedDisposalLine> ooRewList = new ArrayList<>();//委外返工
        List<UnqualifiedDisposalLine> scrList = new ArrayList<>();//报废

        for (UnqualifiedDisposalLine line:lines){
            InspectionBill inspectionBill = line.getInspectionBill();
            if (inspectionBill==null){
                throw new MBootException("未正常关联到质检单！");
            }
            String applyDecision = line.getApplyDecision();//申请决策
            if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.PURCH.getCode())){//采购
                if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                    //handleRec(line);//原处理逻辑（质检单已产生入库）
                    generateStockIn(line);//质检单未产生库存逻辑处理方式
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REJ.getCode())){//判退 不处理
                    //判退时，不处理
                    handleRej(line);
                }else{
                    throw new MBootException("采购业务单仅支持让步接收和判退两种使用决策！");
                }
            }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.MANF.getCode())){//生产
                if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                    //handleRec(line);//原处理逻辑（质检单已产生入库）
                    generateStockIn(line);//质检单未产生库存逻辑处理方式
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                    moRewList.add(line);
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                    scrList.add(line);
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REF.getCode())){//返修
                    handleRepair(line);
                }else{
                    throw new MBootException("生产业务单不支持的使用决策！");
                }
            }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.OUTS.getCode())){//委外
                if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                    //handleRec(line);//原处理逻辑（质检单已产生入库）
                    generateStockIn(line);//质检单未产生库存逻辑处理方式
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                    ooRewList.add(line);
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                    scrList.add(line);
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REF.getCode())){//返修
                    handleRepair(line);
                }else{
                    throw new MBootException("委外业务单不支持的使用决策！");
                }
            }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.INVENTORY.getCode())){//库存质检
                if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                    //handleRec(line);//原处理逻辑（质检单已产生入库）
                    generateStockIn(line);//质检单未产生库存逻辑处理方式
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                    scrList.add(line);
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                    moRewList.add(line);
                }else{
                    throw new MBootException("库存质检业务单仅支持让步接收、报废、返工 使用决策！");
                }
            }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.SALERE.getCode())){//销售退货
                if (applyDecision.equals(InspectionEnums.UsageDecision.REC.getCode())){//让步接收
                    //handleRec(line);//原处理逻辑（质检单已产生入库）
                    generateStockIn(line);//质检单未产生库存逻辑处理方式
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.SCR.getCode())){//报废
                    //判退时，不处理
                    scrList.add(line);
                }else if (applyDecision.equals(InspectionEnums.UsageDecision.REW.getCode())){//返工
                    moRewList.add(line);
                }else{
                    throw new MBootException("销售退货业务单仅支持让步接收、判退、返工 使用决策！");
                }
            }else{
                throw new MBootException("质检单业务类型有误！");//实际业务不会走到该逻辑
            }
        }
        if (moRewList.size()>0){//处理生产返工订单
            Map<String, List<UnqualifiedDisposalLine>> origBizNoMap = moRewList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill().getOriginBizNo()));
            for (String origBizNo :origBizNoMap.keySet()){
                handleRew(origBizNoMap.get(origBizNo),true);//新版
            }
        }
        if (ooRewList.size()>0){//委外返工订单
            Map<String, List<UnqualifiedDisposalLine>> origBizNoMap = ooRewList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill().getOriginBizNo()));
            for (String origBizNo :origBizNoMap.keySet()){
                handleRew(origBizNoMap.get(origBizNo),true);//新版
            }
        }
        if (scrList.size()>0){
            handleScr(scrList,true);
        }
    }

    //质检单不合格，不产生入库批次业务场景对应实现
    // 根据不良品处理单，产生对应入库库存（入库）
    private void generateStockIn(UnqualifiedDisposalLine line){
        /**
         * 不良品处理单明细直接由检验结论不合格的质检产生，且未产生任何入库流水
         * 1.产生入库仓单（自动执行的话：+流水）
         * 2.回写质检单中的字段值（根据不同的策略：回写对应 让步接收、判退、返工、返修、报废）。
         * 3.回写验收单中的字段值（让步接收）。
         * */

        InspectionBill inspectionBill = line.getInspectionBill();
        String originNoticeNo = inspectionBill.getOriginNoticeNo();
        String originBizType = inspectionBill.getOriginBizType();

        QualityOrder inQualityOrder = JpaUtil.getOne(QualityUtils.getQualityOrderClass(originBizType), originNoticeNo);
        String originNoticeLineNo = inspectionBill.getOriginNoticeLineNo();

        NoticeLineKey lineKey = new NoticeLineKey();
        lineKey.setNoticeNo(originNoticeNo);
        lineKey.setLineNo(originNoticeLineNo);
        QualityOrderLine inQualityOrderLine = JpaUtil.getOne(QualityUtils.getQualityOrderLineClass(originBizType), lineKey);//源验收单行


        String applyDecision = line.getApplyDecision();
        boolean autoExecuteWo = false;//入仓单自动执行，jit产生的入库仓单需手动执行

        Item item = JpaUtil.linq(Item.class).idEqual(inspectionBill.getItemCode()).findOne();
        //产生入库仓单（默认已执行完成状态）
        WarehouseOrder inWo = new WarehouseOrder();
        inWo.setAccessType(OrderEnums.AccessType.IN.getCode());
        inWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
        inWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        inWo.setOrderDate(new Date());
        inWo.setOriginBizNo(inspectionBill.getOriginBizNo());
        inWo.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());//关联noticeno字段


        boolean lotStatusLock = false;//库存质检锁定状态
        String feedPlanNoticeNo = "";//送货计划单号
        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){//返工
            inWo.setWoType(NoticeStatusEnums.NoticeType.QREW_IN.getCode());//("53", "不良品处理-返工-转移入")
            inWo.setWhCode("WH0005");// 仓单仓库 指定为不合格品仓：WH0005
            lotStatusLock = true;
            autoExecuteWo = true;
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){//报废
            inWo.setWoType(NoticeStatusEnums.NoticeType.QSCR_IN.getCode());//("55", "不良品处理-报废-转移入")
            inWo.setWhCode("WH0005");// 仓单仓库 指定为不合格品仓：WH0005
            lotStatusLock = true;
            autoExecuteWo = true;
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            inWo.setWoType(NoticeStatusEnums.NoticeType.QO_IN.getCode());//QO_IN("51", "质检让步接收入"),
            //让步接收 仓库取原验收单对应仓库
            if (originBizType.equals(InspectionEnums.OriginBizType.PURCH.getCode())){
                inWo.setWoType(NoticeStatusEnums.NoticeType.PO_IN.getCode());//PO_IN("10", "采购入库"),
            }else if (originBizType.equals(InspectionEnums.OriginBizType.MANF.getCode())){
                inWo.setWoType(NoticeStatusEnums.NoticeType.MO_IN.getCode());//MO_IN("30", "生产成品入库")
            }else if (originBizType.equals(InspectionEnums.OriginBizType.OUTS.getCode())){
                inWo.setWoType(NoticeStatusEnums.NoticeType.OO_IN.getCode());//OO_IN("31", "委外成品入库")
            }/*else if (originBizType.equals(InspectionEnums.OriginBizType.INVENTORY.getCode())){
            }else if (originBizType.equals(InspectionEnums.OriginBizType.SALERE.getCode())){
            }*/
            //让步接收 仓库取原验收单对应仓库
            //QualityOrder inQualityOrder = JpaUtil.getOne(QualityUtils.getQualityOrderClass(originBizType), inspectionBill.getOriginNoticeNo());
            inWo.setWhCode(inQualityOrder.getWhCode());//
            //让步接收自动入库改为人工确认
            //autoExecuteWo = true;
            if (inQualityOrder instanceof InQualityOrder){
                feedPlanNoticeNo = ((InQualityOrder) inQualityOrder).getFeedPlanNoticeNo();
                /*if (StringUtils.isNotBlank(feedPlanNoticeNo)){
                    autoExecuteWo = false;
                }*/
                if (StringUtils.isNotBlank(feedPlanNoticeNo)){
                    FeedPlanNotice feedPlanNotice = JpaUtil.getOne(FeedPlanNotice.class, feedPlanNoticeNo);
                    inWo.setWoType(feedPlanNotice.getPickingType());
                }
            }
        }else{
            throw new MBootException("无效的申请使用决策");
        }
        if (autoExecuteWo){
            inWo.setExecuteTime(new Date());
            inWo.setExecutor("8888");//自动化助手，默认指定用户
            inWo.setOrderStatus(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode());
        }else{
            inWo.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
        }
        JpaUtil.save(inWo);

        WarehouseOrderLine inWoLine = new WarehouseOrderLine();
        inWoLine.setWhCode(inWo.getWhCode());
        inWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        if (item!=null){
            inWoLine.setItemCode(item.getItemCode());
            inWoLine.setItemGroupCode(item.getItemGroupCode());
            inWoLine.setItemName(item.getItemName());
            inWoLine.setItemSpec(item.getItemSpec());
            inWoLine.setUnitCode(item.getUnitCode());
            inWoLine.setDrawingNo(item.getDrawingNo());
        }
        inWoLine.setQuantity(line.getApplyQuantity());//申请数量
        inWoLine.setBizNo(inWo.getBizNo());
        inWoLine.setLineNo("1");
        inWoLine.setOriginBizNo(inspectionBill.getOriginBizNo());
        inWoLine.setOriginBizLineNo(inspectionBill.getOriginBizLineNo());
        inWoLine.setSort("1");

        Lot lot = null;
        List<Lot> lotList = JpaUtil.linq(Lot.class).equal("inspectionBillNo", inspectionBill.getBizNo()).list();
        if (!lotList.isEmpty()){
            lot = lotList.get(0);
        }
        String lotNo = "";
        if (lot==null){
            if (StringUtils.isNotBlank(inQualityOrderLine.getLotNo())){//库存质检、销售退货时，验收单有批次信息，需要延用
                lotNo = inQualityOrderLine.getLotNo();
            }else{
                //产生新批次号
                BizNoticeType bizNoticeType = JpaUtil.getOne(BizNoticeType.class, "Q01");
                StringBuilder expression = new StringBuilder(bizNoticeType.getTypePrefix());
                for(int i=0 ;i < bizNoticeType.getTypeSize(); i++){
                    expression.append("#");
                }
                lotNo = snRuleService.execute(expression.toString(), null).toString()+ "-" + inspectionBill.getOriginNoticeLineNo();
            }
        }else{
            lotNo = lot.getLotNo();
        }
        lot = new Lot();
        lot.setLotNo(lotNo);
        lot.setSubLotIndex(lotService.getCountByLotNo(lot.getLotNo()).toString());//索引
        String binaryString = LotStatusUtil.toBinaryString("0");//默认正常
        if (lotStatusLock){
            lot.setLotStatus(LotStatusUtil.switchBinaryByIndex(binaryString,InspectionEnums.LotStatusBitIndex.IB15.getIndex()));//第15位状态值锁定
        }else{
            lot.setLotStatus(binaryString);//正常状态
        }
        lot.setInspectionBillNo(inspectionBill.getBizNo());//不合格品批次生成时记录对应的质检单单号 溯源
        JpaUtil.save(lot);

        inWoLine.setLotNo(lot.getLotNo());
        inWoLine.setSubLotIndex(lot.getSubLotIndex());//新批次
        inWoLine.setOriginNoticeNo(inspectionBill.getOriginNoticeNo());
        inWoLine.setOriginNoticeLineNo(inspectionBill.getOriginNoticeLineNo());
        JpaUtil.save(inWoLine);

        //自动执行流水
        if (autoExecuteWo){
            InvFlow inFlow = new InvFlow();
            inFlow.setAccessType(inWo.getAccessType());
            inFlow.setItemCode(inWoLine.getItemCode());
            inFlow.setWhCode(inWo.getWhCode());
            inFlow.setQuantity(inWoLine.getQuantity());
            inFlow.setMemo(inWo.getMemo());
            inFlow.setOriginBizNo(inWo.getOriginBizNo());
            inFlow.setOriginBizType(inWo.getOriginBizType());
            inFlow.setOriginBizLineNo(inWoLine.getOriginBizLineNo());
            inFlow.setWoBizNo(inWo.getBizNo());
            inFlow.setWoBizType(inWo.getWoType());
            inFlow.setWoBizLineNo(inWoLine.getLineNo());
            inFlow.setLotNo(inWoLine.getLotNo());
            inFlow.setSubLotIndex(inWoLine.getSubLotIndex());//增加子批索引
            JpaUtil.save(inFlow);
        }

        //处理jit逻辑
        if (StringUtils.isNotBlank(feedPlanNoticeNo)){
            //回写领、补料通知单行数量，以及批次
            FeedPlanNotice feedPlanNotice = JpaUtil.getOne(FeedPlanNotice.class, feedPlanNoticeNo);
            MoPickingNotice pickingNotice = JpaUtil.linq(MoPickingNotice.class).collect("noticeNo", MoPickingNoticeLine.class, "noticeNo")
                    .equal("noticeNo", feedPlanNotice.getSourcePickingNoticeNo()).findOne();
            pickingNotice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CONFIRM.getStatusCode());//确认状态

            List<MoPickingNoticeLine> moPickingNoticeLines = pickingNotice.getMoPickingNoticeLines();//jit对应的领补料通知单都是单行明细
            moPickingNoticeLines.get(0).setQuantity(inWoLine.getQuantity());//确认数量
            moPickingNoticeLines.get(0).setLotNo(inWoLine.getLotNo());
            moPickingNoticeLines.get(0).setSubLotIndex(inWoLine.getSubLotIndex());
            moPickingNoticeLines.get(0).setCrudType(CrudType.UPDATE);
            JpaUtil.update(pickingNotice);//更新pickingNotice及明细行

            //生产的入库仓单需要人工来确认
            //生成待执行的出库仓单
            WarehouseOrder outWo = new WarehouseOrder();
            outWo.setAccessType(pickingNotice.getAccessType());
            outWo.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode());
            outWo.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
            outWo.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
            outWo.setOrderDate(new Date());
            outWo.setOriginBizNo(pickingNotice.getBizOrderNo());
            outWo.setWhCode(pickingNotice.getWhCode());
            outWo.setWoType(pickingNotice.getPickingType());
            outWo.setOriginNoticeNo(pickingNotice.getNoticeNo());//关联noticeno字段
            JpaUtil.save(outWo);

            WarehouseOrderLine outWoLine = new WarehouseOrderLine();
            outWoLine.setWhCode(outWo.getWhCode());
            outWoLine.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
            outWoLine.setItemCode(inWoLine.getItemCode());
            outWoLine.setItemGroupCode(inWoLine.getItemGroupCode());
            outWoLine.setItemName(inWoLine.getItemName());
            outWoLine.setItemSpec(inWoLine.getItemSpec());
            outWoLine.setUnitCode(inWoLine.getUnitCode());
            outWoLine.setDrawingNo(inWoLine.getDrawingNo());
            outWoLine.setQuantity(inWoLine.getQuantity());
            outWoLine.setBizNo(outWo.getBizNo());
            outWoLine.setLineNo("1");
            outWoLine.setOriginBizNo(moPickingNoticeLines.get(0).getOriginBizNo());
            outWoLine.setOriginBizLineNo(moPickingNoticeLines.get(0).getOriginBizLineNo());
            outWoLine.setLotNo(inWoLine.getLotNo());
            outWoLine.setSubLotIndex(inWoLine.getSubLotIndex());
            outWoLine.setOriginNoticeNo(pickingNotice.getNoticeNo());
            outWoLine.setOriginNoticeLineNo(moPickingNoticeLines.get(0).getLineNo());
            JpaUtil.save(outWoLine);
        }

        //回写质检单、验收单明细对应字段
        if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){//返工
            //回写返工数量(质检单)
            JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("reworkQuantity",line.getApplyQuantity()).update();
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())){//报废
            //回写报废数量(质检单)
            JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("scrapQuantity",line.getApplyQuantity()).update();
        }else if (StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())){
            //回写让步接收数量(质检单)
            JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("concessionQuantity",line.getApplyQuantity()).update();
            //更新验收单明细行对应的让步接收数量
            JpaUtil.linu(QualityUtils.getQualityOrderLineClass(originBizType))
                    .equal("noticeNo",inspectionBill.getOriginNoticeNo())
                    .equal("lineNo",inspectionBill.getOriginNoticeLineNo())
                    .set("concessionQuantity",line.getApplyQuantity()).update();
        }else{
            throw new MBootException("无效的申请使用决策");
        }


        line.setSplitNewLotNo(inWoLine.getLotNo());
        line.setSplitNewSubLotIndex(inWoLine.getSubLotIndex());
        line.setSplitNewWhCode(inWo.getWhCode());//后续调用方法逻辑中需要这三个值
        //不良品明细行回写新拆批信息
        JpaUtil.linu(UnqualifiedDisposalLine.class).equal("id",line.getId())
                .set("splitNewWhCode",inWo.getWhCode())
                .set("splitNewLotNo",inWoLine.getLotNo())
                .set("splitNewSubLotIndex",inWoLine.getSubLotIndex())
                .update();
    }
    private void handleRepair(UnqualifiedDisposalLine line){
        InspectionBill inspectionBill = line.getInspectionBill();
        //回写返修数量
        JpaUtil.linu(InspectionBill.class).equal("bizNo",inspectionBill.getBizNo()).set("repairQuantity",line.getApplyQuantity()).update();
    }

    //返工
    private void handleRew(List<UnqualifiedDisposalLine> lines,boolean newversion){
        InspectionBill inspectionBill = lines.get(0).getInspectionBill();
        if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.MANF.getCode())){//生产
            String originBizNo = inspectionBill.getOriginBizNo();
            ManufactureOrder mOrder = JpaUtil.getOne(ManufactureOrder.class, originBizNo);

            ManufactureOrder newMOrder = getManufactureOrder(mOrder,lines.get(0).getApplyQuantity());
            JpaUtil.save(newMOrder);//保存
            int lineno = 0;
            for (UnqualifiedDisposalLine line:lines){
                if (newversion){//新版本
                    generateStockIn(line);
                }else{//原版本
                    lotSplitByApplyDecision(line);//拆分原不合格批
                }
                lineno++;
                ManufactureOrderItem moi = getManufactureOrderItem(line, newMOrder, lineno);
                JpaUtil.save(moi);
            }
        }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.OUTS.getCode())){//委外
            String originBizNo = inspectionBill.getOriginBizNo();
            OutsourceOrder oOrder = JpaUtil.getOne(OutsourceOrder.class, originBizNo);

            OutsourceOrder newOOrder = getOutsourceOrder(oOrder,lines.get(0).getApplyQuantity());
            JpaUtil.save(newOOrder);
            int lineno = 0;
            for (UnqualifiedDisposalLine line:lines){
                if (newversion){//新版本
                    generateStockIn(line);
                }else{//原版本
                    lotSplitByApplyDecision(line);//拆分原不合格批
                }
                lineno++;
                OutsourceOrderItem ooi = getOutsourceOrderItem(line, newOOrder, lineno);
                JpaUtil.save(ooi);
            }
        }else if (inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.INVENTORY.getCode())
                ||inspectionBill.getOriginBizType().equals(InspectionEnums.OriginBizType.SALERE.getCode())){//销售退、库存质检
            //生成对应的返工订单
            for (UnqualifiedDisposalLine line:lines){
                ManufactureOrder newMOrder = getManufactureOrder(line);
                JpaUtil.save(newMOrder);//保存

                if (newversion){//新版本
                    generateStockIn(line);
                }else{//原版本
                    lotSplitByApplyDecision(line);//拆分原不合格批
                }
                ManufactureOrderItem moi = getManufactureOrderItem(line, newMOrder, 1);
                JpaUtil.save(moi);
            }
        }else{
            throw new MBootException("不支持的业务单类型");
        }
    }

    private OutsourceOrderItem getOutsourceOrderItem(UnqualifiedDisposalLine line, OutsourceOrder newOOrder, int lineno) {
        InspectionBill lineInspectionBill = line.getInspectionBill();
        OutsourceOrderItem ooi = new OutsourceOrderItem();
        ooi.setBizNo(newOOrder.getBizNo());
        ooi.setLineNo(lineno +"");
        ooi.setDrawingNo(lineInspectionBill.getDrawingNo());
        ooi.setItemCode(lineInspectionBill.getItemCode());
        ooi.setItemName(lineInspectionBill.getItemName());
        ooi.setItemSpec(lineInspectionBill.getItemSpec());
        ooi.setLotNo(line.getSplitNewLotNo());
        ooi.setSubLotIndex(line.getSplitNewSubLotIndex());
        ooi.setWhCode(line.getSplitNewWhCode());
        ooi.setUnitCode(lineInspectionBill.getUnitCode());
        ooi.setQuantity(line.getApplyQuantity());
        return ooi;
    }

    private ManufactureOrderItem getManufactureOrderItem(UnqualifiedDisposalLine line, ManufactureOrder newMOrder, int lineno) {
        InspectionBill lineInspectionBill = line.getInspectionBill();
        ManufactureOrderItem moi = new ManufactureOrderItem();
        moi.setBizNo(newMOrder.getBizNo());
        moi.setLineNo(lineno +"");
        moi.setDrawingNo(lineInspectionBill.getDrawingNo());
        moi.setItemCode(lineInspectionBill.getItemCode());
        moi.setItemName(lineInspectionBill.getItemName());
        moi.setItemSpec(lineInspectionBill.getItemSpec());
        moi.setLotNo(line.getSplitNewLotNo());
        moi.setSubLotIndex(line.getSplitNewSubLotIndex());
        moi.setWhCode(line.getSplitNewWhCode());
        moi.setUnitCode(lineInspectionBill.getUnitCode());
        moi.setQuantity(line.getApplyQuantity());
        return moi;
    }

    private OutsourceOrder getOutsourceOrder(OutsourceOrder oOrder,BigDecimal orderQuantity) {
        OutsourceOrder newOOrder = new OutsourceOrder();
        newOOrder.setBizMan(oOrder.getBizMan());
        newOOrder.setCloseStatus(oOrder.getCloseStatus());
        newOOrder.setEndDate(oOrder.getEndDate());
        newOOrder.setOrderType(OrderEnums.OutsourceOrderType.REWORK.getCode());
        newOOrder.setEntrustDept(oOrder.getEntrustDept());
        newOOrder.setMachiningDrawing(oOrder.getMachiningDrawing());
        newOOrder.setMemo(oOrder.getMemo());
        newOOrder.setOrderDate(oOrder.getOrderDate());
        newOOrder.setOrderQuantity(orderQuantity);
        newOOrder.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
        newOOrder.setPlanner(oOrder.getPlanner());
        newOOrder.setPnCode(oOrder.getPnCode());
        newOOrder.setPnName(oOrder.getPnName());
        newOOrder.setProductDrawingNo(oOrder.getProductDrawingNo());
        newOOrder.setProductItemCode(oOrder.getProductItemCode());
        newOOrder.setProductItemName(oOrder.getProductItemName());
        newOOrder.setReferenceDate(oOrder.getReferenceDate());
        newOOrder.setStartDate(oOrder.getStartDate());
        newOOrder.setUnitCode(oOrder.getUnitCode());
        return newOOrder;
    }

    private ManufactureOrder getManufactureOrder(ManufactureOrder mOrder, BigDecimal orderQuantity) {
        ManufactureOrder newMOrder = new ManufactureOrder();
        newMOrder.setCloseStatus(mOrder.getCloseStatus());
        newMOrder.setEndDate(mOrder.getEndDate());
        newMOrder.setMainWorkshop(mOrder.getMainWorkshop());
        newMOrder.setMemo(mOrder.getMemo());
        newMOrder.setOrderDate(mOrder.getOrderDate());
        newMOrder.setOrderQuantity(orderQuantity);
        newMOrder.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());//计划
        newMOrder.setOrderType(OrderEnums.ManufactureOrderType.REWORK.getCode());//
        newMOrder.setPlanner(mOrder.getPlanner());
        newMOrder.setProductDrawingNo(mOrder.getProductDrawingNo());
        newMOrder.setProductItemCode(mOrder.getProductItemCode());
        newMOrder.setProductItemName(mOrder.getProductItemName());
        newMOrder.setItemSpec(mOrder.getItemSpec());
        newMOrder.setReferenceDate(mOrder.getReferenceDate());
        newMOrder.setStartDate(mOrder.getStartDate());
        newMOrder.setUnitCode(mOrder.getUnitCode());
        newMOrder.setWorkCenterCode(mOrder.getWorkCenterCode());
        return newMOrder;
    }
    private ManufactureOrder getManufactureOrder(UnqualifiedDisposalLine line) {
        InspectionBill lineInspectionBill = line.getInspectionBill();
        String itemCode = lineInspectionBill.getItemCode();
        Item item = JpaUtil.getOne(Item.class, itemCode);

        ManufactureOrder order = new ManufactureOrder();
        order.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());//230414 默认状态由plan改为下达
        order.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
        order.setMainWorkshop(item.getMainWorkshop());
        order.setWorkCenterCode(item.getWorkCenterCode());
        order.setStartDate(new Date());
        order.setEndDate(DateUtils.addDays(new Date(),7));
        order.setReferenceDate(new Date());//取当前日期
        order.setOrderQuantity(line.getApplyQuantity());
        order.setOrderDate(new Date());
        order.setOrderType(OrderEnums.ManufactureOrderType.REWORK.getCode());//返工

        order.setProductItemCode(item.getItemCode());
        order.setProductItemName(item.getItemName());
        order.setProductDrawingNo(item.getDrawingNo());
        order.setItemSpec(item.getItemSpec());
        order.setUnitCode(item.getUnitCode());
        return order;
    }

    private void handleScr(List<UnqualifiedDisposalLine> lines,boolean newversion){//处理报废
        if (newversion){
            for (UnqualifiedDisposalLine line : lines){
                generateStockIn(line);//先入库
            }
            Map<String, List<UnqualifiedDisposalLine>> whcodeGroupMap = lines.stream().collect(Collectors.groupingBy(UnqualifiedDisposalLine::getSplitNewWhCode));
            for (String whcode: whcodeGroupMap.keySet()){
                ScrapOutApply apply = new ScrapOutApply();
                apply.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode());
                apply.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
                apply.setMemo("由不良品申请单生成");
                apply.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
                apply.setWhCode(whcode);
                JpaUtil.save(apply);

                List<UnqualifiedDisposalLine> sublines = whcodeGroupMap.get(whcode);
                int lineno = 0;
                for (UnqualifiedDisposalLine line : sublines){
                    lineno++;
                    ScrapOutApplyLine scrapOutApplyLine = getScrapOutApplyLine(line, apply, lineno);
                    JpaUtil.save(scrapOutApplyLine);
                }
            }
        }else{
            Map<String, List<UnqualifiedDisposalLine>> whcodeGroupMap = lines.stream().collect(Collectors.groupingBy(UnqualifiedDisposalLine::getWhCode));
            for (String whcode: whcodeGroupMap.keySet()){
                ScrapOutApply apply = new ScrapOutApply();
                apply.setBpmnStatus(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode());
                apply.setCloseStatus(OrderStatusEnums.CloseStatus.OPEN.getStatusCode());
                apply.setMemo("由不良品申请单生成");
                apply.setOrderStatus(OrderStatusEnums.OrderStatus.PLAN.getStatusCode());
                apply.setWhCode(whcode);
                JpaUtil.save(apply);

                List<UnqualifiedDisposalLine> sublines = whcodeGroupMap.get(whcode);
                int lineno = 0;
                for (UnqualifiedDisposalLine line : sublines){
                    lotSplitByApplyDecision(line);//拆分原不合格批
                    //UnqualifiedDisposalLine dbLine = JpaUtil.getOne(UnqualifiedDisposalLine.class, line.getId());
                    lineno++;
                    ScrapOutApplyLine scrapOutApplyLine = getScrapOutApplyLine(line, apply, lineno);
                    JpaUtil.save(scrapOutApplyLine);
                }

            }
        }
    }

    private ScrapOutApplyLine getScrapOutApplyLine(UnqualifiedDisposalLine line, ScrapOutApply apply, int lineno) {
        ScrapOutApplyLine scrapOutApplyLine = new ScrapOutApplyLine();
        InspectionBill bill = line.getInspectionBill();
        scrapOutApplyLine.setBizNo(apply.getBizNo());
        scrapOutApplyLine.setDrawingNo(bill.getDrawingNo());
        scrapOutApplyLine.setItemCode(bill.getItemCode());
        scrapOutApplyLine.setItemName(bill.getItemName());
        scrapOutApplyLine.setItemSpec(bill.getItemSpec());
        scrapOutApplyLine.setUnitCode(bill.getUnitCode());
        scrapOutApplyLine.setLineNo(lineno +"");
        scrapOutApplyLine.setLotNo(line.getSplitNewLotNo());
        scrapOutApplyLine.setSubLotIndex(line.getSplitNewSubLotIndex());
        scrapOutApplyLine.setQuantity(line.getApplyQuantity());
        scrapOutApplyLine.setScrapReason("不良品申请单处理结果:报废");
        scrapOutApplyLine.setQcStatus(line.getApplyDecision());//质检结果
        return scrapOutApplyLine;
    }

    private void checkOriginBizDecision(List<UnqualifiedDisposalLine> lineList) {
        if (lineList.isEmpty()){
            throw new MBootException("请添加明细行！");//由于先执行了save事务保存，此处需要抛出异常回滚，而非return Result.error
        }
        for (UnqualifiedDisposalLine line:lineList){
            String applyDecision = line.getApplyDecision();
            InspectionBill inspectionBill = line.getInspectionBill();
            if (StringUtils.equals(InspectionEnums.OriginBizType.PURCH.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REJ.getCode())){
                    throw new MBootException("仅支持让步接收和判退两种使用决策！");
                }
            }else if (StringUtils.equals(InspectionEnums.OriginBizType.MANF.getCode(),inspectionBill.getOriginBizType())
                    ||StringUtils.equals(InspectionEnums.OriginBizType.OUTS.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REF.getCode())){
                    throw new MBootException("仅支持让步接收、返工、报废、返修使用决策！");
                }
            }else if (StringUtils.equals(InspectionEnums.OriginBizType.INVENTORY.getCode(),inspectionBill.getOriginBizType())
                    ||StringUtils.equals(InspectionEnums.OriginBizType.SALERE.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.SCR.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){
                    throw new MBootException("仅支持让步接收、报废、返工使用决策！");
                }
            }else{
                throw new MBootException("不支持的源单类型！");
            }/*else if (StringUtils.equals(InspectionEnums.OriginBizType.SALERE.getCode(),inspectionBill.getOriginBizType())){
                if (!StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REC.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REJ.getCode())&&
                        !StringUtils.equals(applyDecision,InspectionEnums.UsageDecision.REW.getCode())){
                    throw new MBootException("仅支持让步接收、判退、返工使用决策！");
                }
            }*/
        }
        Map<String, List<UnqualifiedDisposalLine>> collect = lineList.stream().collect(Collectors.groupingBy(l -> l.getInspectionBill() + l.getApplyDecision()));
        for (String key :collect.keySet()){
            List<UnqualifiedDisposalLine> unqualifiedDisposalLines = collect.get(key);
            if (unqualifiedDisposalLines.size()>1){
                throw new MBootException("重复的使用决策！");
            }
        }
    }
}

